As part of “bringing up” a multiple central processing unit (CPU) system, an operating system (OS) that is executing on a bootstrap CPU (the CPU on which an OS kernel is initialized first on) brings up one or more secondary CPUs (here bring-up refers to the OS procedure for initializing the secondary CPUs). Each secondary CPU starts executing in a known initial state that is defined by the architecture or firmware. Typically, in this initial state, virtual memory translation is not performed—virtual addresses (VAs) identity map to physical addresses (PAs). During bring-up, a memory management unit (MMU) is activated and the initial known state is supplanted by an operational state in which the MMU translates VAs to PAs based on a page table translation hierarchy tailored for the specific secondary CPU.
Since the manner in which the secondary CPU interprets addresses for data and instruction fetches is dramatically impacted by activating the MMU, the bring-up may be corrupted unless the bring-up code, also known as the initialization code, is located at the same addresses irrespective of the MMU state. More specifically, suppose that the MMU is activated and the bring-up code is not located at the same address before and after activating the MMU. In such a scenario, although instructions may continue to use stale mappings and execute as expected until translation lookaside buffer entries have been flushed, eventually the secondary CPU will execute an instruction fetch that either fails or returns an unintended value compromising the bring-up process. Since VAs are equal to PAs in the initial state, ensuring that the addresses of the bring-up code are unchanged when the MMU is activated is known as “mapping” the bring-up code “1:1.” 1:1 is also referred to as identify mapping, in which the value of the VA is the same as the PA in the mapping.
In this 1:1 mapping approach, choosing a memory location for the bring-up code involves selecting an address for both the PA and the VA of the bring-up code that does not conflict with any kernel code or data. On some architectures, choosing such a memory location is relatively easy. For instance, on Intel®IA-32 and AMD®64 architectures, the bring-up code is typically located in memory below 1 MB—an area of memory that is usually reserved in advance, and that does not include PAs for OS kernel code and data structures.
By contrast, on other architectures, selecting a valid 1:1 mapping for the bring-up code is more difficult. For instance, on ARM®64 architectures memory may be located at arbitrary locations for varying platform implementations. Consequently, ensuring that an address for both the PA and the VA of the bring-up code does not match a VA that corresponds to valid kernel code or data may be impossible. If the PA for the bring-up code is equivalent to a VA that corresponds to valid kernel code or data, then the execution flow of the bring-up code is unintentionally diverted to this valid kernel code or data when the MMU is activated, and bring-up will typically fail. Consequently, a more flexible and comprehensive approach to initializing MMUs during bring-up of secondary CPUs is desirable.